package net.pws.common.security.filter;

import java.io.IOException;
import java.util.UUID;

import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.pws.common.util.StringUtils;
import net.pws.common.security.PrincipalManagerFactory;
import net.pws.common.security.SecurityContext;
import net.pws.common.security.spi.AuthenticateFailedException;
import net.pws.common.security.spi.AuthenticateProvider;
import net.pws.common.security.spi.Principal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.tfs.Licence;
import org.apache.commons.tfs.LicenceFactory;


public class WebAuthenticateProcessorHandler extends AbstractAuthenticateFilter {

	private static final Log logger = LogFactory
			.getLog(WebAuthenticateProcessorHandler.class);

	private AuthenticateProvider authenticateProvider;
	
	private CaptchaValidator captchaValidator;
	
	private LoginLogProvider loginLogProvider;

	public WebAuthenticateProcessorHandler() {
		super();
	}

	public WebAuthenticateProcessorHandler(
			AuthenticateProvider authenticateProvider) {
		super();
		this.authenticateProvider = authenticateProvider;
	}

	public AuthenticateProvider getAuthenticateProvider() {
		return authenticateProvider;
	}

	public void setAuthenticateProvider(
			AuthenticateProvider authenticateProvider) {
		this.authenticateProvider = authenticateProvider;
	}

	public CaptchaValidator getCaptchaValidator() {
        return captchaValidator;
    }

    public void setCaptchaValidator(CaptchaValidator captchaValidator) {
        this.captchaValidator = captchaValidator;
    }
    
	public LoginLogProvider getLoginLogProvider() {
		return loginLogProvider;
	}

	public void setLoginLogProvider(LoginLogProvider loginLogProvider) {
		this.loginLogProvider = loginLogProvider;
	}

    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain) throws IOException,
                                           ServletException {
        if (!(request instanceof HttpServletRequest)) {
            throw new ServletException("Can only process HttpServletRequest");
        }
        
        if (!(response instanceof HttpServletResponse)) {
            throw new ServletException("Can only process HttpServletResponse");
        }
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        
        String username = getUserName(httpRequest);
        String password = getPassword(httpRequest);
        
        try {
        	// verify lcs
        	Licence licence = LicenceFactory.getInstance().getLicence();
			if(!licence.validate()) {
        		throw new AuthenticateFailedException(licence.getErrorMessage());
        	}
			
			if (captchaValidator != null && !captchaValidator.validate(httpRequest, httpResponse)) {
			    throw new AuthenticateFailedException("验证码错误！");
			}

            Principal principal = authenticateProvider.authenticate(username,
                                                                    password);
            if (principal == null || StringUtils.isEmpty(principal.getId())) {
                throw new AuthenticateFailedException("用户名或密码错误！");
            }
            if (!principal.isWebAccessAllowed()) {
                throw new AuthenticateFailedException("该用户无WEB访问权限！");
            }
            
            String token = UUID.randomUUID().toString();
            
            PrincipalManagerFactory.getInstance().put(token, principal);
            SecurityContext.setContext(principal);
            saveCookie(httpResponse, AUTH_TOKEN_KEY, token, -1);
            
            request.setAttribute(AUTHENTICATED_SUCCEED_KEY, Boolean.TRUE);
            
            if (loginLogProvider != null) {
            	loginLogProvider.log(principal, httpRequest, httpResponse);
            }
            
            chain.doFilter(request, response);
        }
        catch (Exception e) {
            logger.error(e, e);
            httpRequest.setAttribute("authError", e);
            RequestDispatcher rd = request.getRequestDispatcher(getLoginPage());
            rd.forward(request, response);
            return;
            //(httpResponse).sendRedirect(getLoginPage());
        }
    }
}
